import folium
import os
from folium.plugins import MiniMap, MarkerCluster
from folium.raster_layers import TileLayer
import numpy as np
from src.data_handler import DataHandler

class RouteMapper:
    """
    校园周边跑步路线图生成器
    使用folium库创建交互式地图，展示跑步路线、距离和坡度信息
    """
    
    def __init__(self, output_dir=None):
        self.output_dir = output_dir or os.path.join(
            os.path.dirname(__file__), '..', 'data', 'maps')
        self.data_handler = DataHandler()
        
        # 确保输出目录存在
        os.makedirs(self.output_dir, exist_ok=True)
        
        # 学校默认位置（北京），实际使用时应从配置中获取
        self.school_lat = 39.9042
        self.school_lon = 116.4074
        self.default_zoom = 15
    
    def create_route_map(self, route_id=None, all_routes=False):
        """
        创建跑步路线地图
        
        Args:
            route_id: 特定路线的ID，如果为None且all_routes为False，则显示推荐路线
            all_routes: 是否显示所有路线
            
        Returns:
            生成的HTML文件路径
        """
        # 创建地图实例
        m = folium.Map(
            location=[self.school_lat, self.school_lon],
            zoom_start=self.default_zoom,
            tiles='OpenStreetMap',
            control_scale=True
        )
        
        # 添加小地图插件
        minimap = MiniMap()
        m.add_child(minimap)
        
        # 添加学校标记
        folium.Marker(
            location=[self.school_lat, self.school_lon],
            popup="<b>学校</b>",
            tooltip="学校位置",
            icon=folium.Icon(color='red', icon='university', prefix='fa')
        ).add_to(m)
        
        # 获取路线数据
        routes = self.data_handler.load_routes()
        
        # 添加路线
        if all_routes:
            # 显示所有路线
            self._add_all_routes(m, routes)
            filename = "all_routes_map.html"
        else:
            # 显示特定路线或推荐路线
            if route_id:
                route = next((r for r in routes if r['id'] == route_id), None)
                if not route:
                    print(f"未找到ID为{route_id}的路线")
                    route = self.data_handler.get_recommended_route()
            else:
                route = self.data_handler.get_recommended_route()
            
            if route:
                self._add_route(m, route)
                filename = f"route_{route['id']}_{route['name']}.html".replace(' ', '_')
            else:
                print("没有可用的路线数据")
                filename = "empty_map.html"
        
        # 添加图层控制
        folium.LayerControl().add_to(m)
        
        # 保存地图
        output_path = os.path.join(self.output_dir, filename)
        m.save(output_path)
        print(f"路线图已保存至: {output_path}")
        return output_path
    
    def _add_all_routes(self, map_obj, routes):
        """在地图上添加所有路线"""
        # 创建标记聚类
        marker_cluster = MarkerCluster().add_to(map_obj)
        
        # 为不同难度的路线定义不同颜色
        difficulty_colors = {
            "简单": "green",
            "中等": "orange",
            "困难": "red"
        }
        
        # 添加每条路线
        for route in routes:
            color = difficulty_colors.get(route.get('difficulty', '中等'), 'blue')
            self._add_route(map_obj, route, color=color, marker_cluster=marker_cluster)
        
        # 添加路线信息图例
        self._add_route_legend(map_obj, difficulty_colors)
    
    def _add_route(self, map_obj, route, color='blue', marker_cluster=None):
        """在地图上添加单条路线"""
        # 获取路线坐标
        path_coords = [(point['lat'], point['lng']) for point in route.get('path', [])]
        
        if not path_coords:
            print(f"路线 {route.get('name', '未知')} 没有坐标数据")
            return
        
        # 添加路线线条
        folium.PolyLine(
            path_coords,
            color=color,
            weight=4,
            opacity=0.7,
            dash_array='10, 5',
            tooltip=f"{route['name']} - {route['distance']}km",
            popup=self._create_route_popup(route)
        ).add_to(map_obj)
        
        # 添加起点标记
        folium.Marker(
            location=path_coords[0],
            popup=f"<b>{route['name']}</b><br>起点",
            tooltip="起点",
            icon=folium.Icon(color='green', icon='flag', prefix='fa')
        ).add_to(marker_cluster if marker_cluster else map_obj)
        
        # 添加终点标记（如果路线是闭合的，就不重复标记）
        if len(path_coords) > 1 and not self._are_coords_equal(path_coords[0], path_coords[-1]):
            folium.Marker(
                location=path_coords[-1],
                popup=f"<b>{route['name']}</b><br>终点",
                tooltip="终点",
                icon=folium.Icon(color='red', icon='flag-checkered', prefix='fa')
            ).add_to(marker_cluster if marker_cluster else map_obj)
        
        # 添加路线中点标记，显示详细信息
        mid_point_idx = len(path_coords) // 2
        folium.Marker(
            location=path_coords[mid_point_idx],
            popup=self._create_route_popup(route),
            tooltip=f"{route['name']} - 点击查看详情",
            icon=folium.Icon(color=color, icon='info-circle', prefix='fa')
        ).add_to(marker_cluster if marker_cluster else map_obj)
        
        # 如果有高程数据，可以添加高程图表
        if self._should_add_elevation(route):
            self._add_elevation_chart(map_obj, route, path_coords)
    
    def _create_route_popup(self, route):
        """创建路线详细信息弹出框"""
        popup_html = f"""
        <div style="font-family: Arial, sans-serif; max-width: 300px;">
            <h4 style="color: #2c3e50; margin-top: 0;">{route['name']}</h4>
            <table style="width: 100%; border-collapse: collapse;">
                <tr>
                    <td style="padding: 5px; border-bottom: 1px solid #eee;"><strong>距离:</strong></td>
                    <td style="padding: 5px; border-bottom: 1px solid #eee;">{route['distance']} 公里</td>
                </tr>
                <tr>
                    <td style="padding: 5px; border-bottom: 1px solid #eee;"><strong>爬升:</strong></td>
                    <td style="padding: 5px; border-bottom: 1px solid #eee;">{route['elevation_gain']} 米</td>
                </tr>
                <tr>
                    <td style="padding: 5px; border-bottom: 1px solid #eee;"><strong>难度:</strong></td>
                    <td style="padding: 5px; border-bottom: 1px solid #eee;">
                        <span style="padding: 2px 8px; border-radius: 12px; background-color: {self._get_difficulty_color(route['difficulty'])};">
                            {route['difficulty']}
                        </span>
                    </td>
                </tr>
            </table>
            <div style="margin-top: 10px; font-size: 14px; color: #555;">
                <strong>描述:</strong><br>
                {route.get('description', '暂无描述')}
            </div>
        </div>
        """
        return popup_html
    
    def _get_difficulty_color(self, difficulty):
        """根据难度返回对应的颜色"""
        colors = {
            "简单": "#27ae60",
            "中等": "#f39c12",
            "困难": "#e74c3c"
        }
        return colors.get(difficulty, "#3498db")
    
    def _should_add_elevation(self, route):
        """判断是否应该添加高程图表"""
        # 简单判断：如果有爬升数据且大于0，则添加
        return route.get('elevation_gain', 0) > 0
    
    def _add_elevation_chart(self, map_obj, route, path_coords):
        """添加高程图表（模拟数据）"""
        # 注意：实际应用中应该使用真实的高程数据
        # 这里我们使用模拟数据来演示
        try:
            # 生成模拟的高程数据
            distance = route['distance'] * 1000  # 转换为米
            elevation_gain = route['elevation_gain']
            
            # 创建简单的高程轮廓
            n_points = len(path_coords)
            elevations = []
            
            # 创建一个简单的山地轮廓
            for i in range(n_points):
                # 生成一些起伏
                progress = i / (n_points - 1) if n_points > 1 else 0
                # 正弦波生成起伏，加上一些随机变化
                elevation = elevation_gain * (0.5 + 0.5 * np.sin(progress * np.pi * 4)) \
                           * (0.8 + 0.2 * np.random.random())
                elevations.append(round(elevation, 1))
            
            # 创建高程数据的HTML表格
            elevation_html = """
            <div style="font-family: Arial, sans-serif; max-width: 300px;">
                <h5 style="margin-top: 0;">高程信息</h5>
                <div style="font-size: 14px; margin-bottom: 10px;">
                    总爬升: <strong>{elevation_gain} 米</strong>
                </div>
                <div style="border: 1px solid #ddd; padding: 10px; background-color: #f9f9f9;">
                    <canvas id="elevationChart" width="280" height="120"></canvas>
                </div>
                <script>
                    // 简单的高程图表绘制
                    var ctx = document.getElementById('elevationChart').getContext('2d');
                    var elevations = {elevations};
                    
                    // 绘制简单的折线图
                    ctx.beginPath();
                    ctx.moveTo(0, 120 - (elevations[0] / {max_elevation} * 100 + 10));
                    
                    for (var i = 1; i < elevations.length; i++) {{
                        var x = (i / (elevations.length - 1)) * 280;
                        var y = 120 - (elevations[i] / {max_elevation} * 100 + 10);
                        ctx.lineTo(x, y);
                    }}
                    
                    ctx.strokeStyle = '#3498db';
                    ctx.lineWidth = 2;
                    ctx.stroke();
                    
                    // 添加简单的坐标轴标签
                    ctx.fillStyle = '#666';
                    ctx.font = '10px Arial';
                    ctx.fillText('起点', 0, 115);
                    ctx.fillText('终点', 260, 115);
                    ctx.fillText('{max_elevation}m', 5, 15);
                    ctx.fillText('0m', 5, 115);
                </script>
            </div>
            """.format(
                elevation_gain=elevation_gain,
                elevations=elevations,
                max_elevation=max(elevations) * 1.2  # 给最高点留一些空间
            )
            
            # 创建高程信息弹窗
            popup = folium.Popup(elevation_html, max_width=350)
            
            # 在路线中点添加高程图表标记
            mid_point_idx = len(path_coords) // 2
            folium.Marker(
                location=path_coords[mid_point_idx],
                popup=popup,
                tooltip="查看高程信息",
                icon=folium.Icon(color='purple', icon='area-chart', prefix='fa')
            ).add_to(map_obj)
            
        except Exception as e:
            print(f"添加高程图表失败: {e}")
    
    def _add_route_legend(self, map_obj, difficulty_colors):
        """添加路线图例"""
        legend_html = """
        <div style="position: fixed; bottom: 50px; left: 50px; z-index: 1000;">
            <div style="background-color: white; padding: 10px; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.2);">
                <h5 style="margin-top: 0; font-family: Arial, sans-serif;">路线难度</h5>
                {legend_items}
            </div>
        </div>
        """
        
        legend_items = ""
        for difficulty, color in difficulty_colors.items():
            legend_items += f"""
            <div style="display: flex; align-items: center; margin: 5px 0; font-family: Arial, sans-serif; font-size: 14px;">
                <div style="width: 20px; height: 3px; background-color: {color}; margin-right: 8px;"></div>
                <span>{difficulty}</span>
            </div>
            """
        
        # 将图例添加到地图
        map_obj.get_root().html.add_child(folium.Element(legend_html.format(legend_items=legend_items)))
    
    def _are_coords_equal(self, coord1, coord2, tolerance=0.00001):
        """判断两个坐标是否相等（考虑浮点数精度）"""
        return (abs(coord1[0] - coord2[0]) < tolerance and 
                abs(coord1[1] - coord2[1]) < tolerance)
    
    def create_detailed_route_map(self, route_id):
        """创建详细的单条路线地图，包含更多信息"""
        # 这个方法可以扩展为包含更详细的路线信息
        # 目前直接调用create_route_map
        return self.create_route_map(route_id=route_id, all_routes=False)
    
    def generate_all_maps(self):
        """生成所有路线的地图"""
        # 生成总览图
        overview_map = self.create_route_map(all_routes=True)
        
        # 获取所有路线
        routes = self.data_handler.load_routes()
        
        # 为每条路线生成单独的地图
        individual_maps = []
        for route in routes:
            map_path = self.create_route_map(route_id=route['id'])
            individual_maps.append({
                'route_id': route['id'],
                'route_name': route['name'],
                'map_path': map_path
            })
        
        return {
            'overview_map': overview_map,
            'individual_maps': individual_maps
        }


if __name__ == "__main__":
    # 示例使用
    mapper = RouteMapper()
    
    # 生成所有路线的总览图
    print("生成所有路线总览图...")
    mapper.create_route_map(all_routes=True)
    
    # 生成推荐路线图
    print("\n生成推荐路线图...")
    mapper.create_route_map()
    
    # 生成所有地图
    print("\n生成所有地图...")
    all_maps = mapper.generate_all_maps()
    print(f"已生成 {len(all_maps['individual_maps'])} 个路线图和 1 个总览图")